#include "evalequa.h"
#include <algorithm>
#include <cmath>
#include <string>
#include <iostream>
#include <iterator>

double evaluerstring(double temps,const std::string& chaine,unsigned posdeb,unsigned posfin)
{
	double resultat=0;
	if (chaine[posdeb]=='t')
		return temps;
	char entiers[]={'0','1','2','3','4','5','6','7','8','9'};
	if (std::any_of(entiers,entiers+10,[chaine,posdeb](char c){ return c==chaine[posdeb]; }))
	{
		std::string nombre(chaine.begin()+posdeb,chaine.begin()+posfin+1);
		return std::stod(nombre);
	}
	if (chaine[posdeb]=='(')
	{
		int compteur=0;
		unsigned esp=std::distance(chaine.begin(),std::find_if(chaine.begin()+posdeb+3,chaine.begin()+posfin-1,[&compteur](char c)
		{ 
			if (c=='(') compteur++;
			if (c==')') compteur--;
			if (c==' '&&compteur==0) return true;
			return false;
		}));
		switch (chaine[posdeb+1])
		{
		case '+':
			resultat+=evaluerstring(temps,chaine,posdeb+3,esp-1);
			resultat+=evaluerstring(temps,chaine,esp+1,posfin-1);
			return resultat;
			break;
		case '-':
			resultat+=evaluerstring(temps,chaine,posdeb+3,esp-1);
			resultat-=evaluerstring(temps,chaine,esp+1,posfin-1);
			return resultat;
			break;
		case '*':
			resultat+=evaluerstring(temps,chaine,posdeb+3,esp-1);
			resultat*=evaluerstring(temps,chaine,esp+1,posfin-1);
			return resultat;
			break;
		case '/':
			resultat+=evaluerstring(temps,chaine,posdeb+3,esp-1);
			resultat/=evaluerstring(temps,chaine,esp+1,posfin-1);
			return resultat;
			break;
		case 's':
			return std::sin(evaluerstring(temps,chaine,posdeb+3,posfin-1));
			break;
		case 'c':
			return std::cos(evaluerstring(temps,chaine,posdeb+3,posfin-1));
			break;
		case 't':
			return std::tan(evaluerstring(temps,chaine,posdeb+3,posfin-1));
			break;
		case 'e':
			return std::exp(evaluerstring(temps,chaine,posdeb+3,posfin-1));
			break;
		default:
			break;
		}
	}
	return 0;
}

EvalEqua::EvalEqua(): equationx(), equationy(), equationz()
{

}

EvalEqua::EvalEqua(std::string x,std::string y,std::string z): equationx(x), equationy(y), equationz(z)
{

}

EvalEqua& EvalEqua::operator=(const EvalEqua& E)
{
	equationx=E.equationx;
	equationy=E.equationy;
	equationz=E.equationz;
	return *this;
}

point EvalEqua::evaluer(double temps)
{
	double x,y,z;
	x=evaluerstring(temps,equationx,0,equationx.size()-1);
	y=evaluerstring(temps,equationy,0,equationy.size()-1);
	z=evaluerstring(temps,equationz,0,equationz.size()-1);
	point p(x,y,z);
	return p;
}

